package es.uji.viselab.util;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.logging.FileHandler;
import java.util.logging.Logger;
import java.util.logging.SimpleFormatter;
import java.awt.FlowLayout;
import java.awt.TextArea;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;

import javax.swing.BoxLayout;
import javax.swing.JComboBox;
import javax.swing.JPanel;

import es.uji.viselab.ViSeLabComponent;

public class LogRecorder implements ViSeLabComponent, ActionListener {

	static LogLevel currentLogLevel=LogLevel.DEBUG;
	static TextArea textLogArea= new TextArea(10, 60);
	
	static Logger logger;
	static FileHandler fh;
	static final boolean useLogFile = true;
	static LogRecorder instance;
	JPanel rootPanel;
	JComboBox availableVerbosityLevel;

	private LogRecorder(){}
	
	public static void log(LogLevel level, String m, String m2) {
		if (currentLogLevel.show(level)) {
			SimpleDateFormat formatter = new SimpleDateFormat("hh:mm:ss");
			Date date = new Date();
			String t = formatter.format(date);
			String logEntry = t + ": " + m + "\n";
			if (m2 != null) {
				logEntry = logEntry + "> " + m2 + "\n";
			}
			writeTextArea(logEntry);
			if (useLogFile)
				writeFile(level, logEntry);
		}
	}

	private static void writeFile(LogLevel level, String logEntry) {

		// First-time use
		if (fh == null || logger == null) {
			logger = Logger.getLogger("ViSeLabLog");
			int limit = 1000000; // 1 Mb
			try {
				fh = new FileHandler("ViSeLab.log", limit, 1, true);
			} catch (SecurityException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			} // 1 file to cycle, true= append files
			logger.addHandler(fh);
			// logger.setLevel(Level.ALL);
			SimpleFormatter formatter = new SimpleFormatter();
			fh.setFormatter(formatter);
		}
		try {
			if (level == LogLevel.ERROR) {
				logger.severe(logEntry);
			} else if (level == LogLevel.STATS) 
				logger.info(logEntry);
		} catch (SecurityException e) {
			e.printStackTrace();
		}
	}

	protected static void writeTextArea(String s) {
		if (textLogArea != null) {
			textLogArea.setText(s + textLogArea.getText());
		}
	}

	public static void setTextAreaLog(TextArea ta) {
		textLogArea = ta;
	}

	public static void log(LogLevel level, String m) {
		log(level, m, null);
	}

	public static void setLogLevel(LogLevel verbosityLevel) {
		currentLogLevel = verbosityLevel;

	}

	public static LogRecorder getInstance() {
		if (instance==null)
			instance=new LogRecorder();
		return instance;
	}

	@Override
	public String getPanelTitle() {
		return "Log";
	}

	@Override
	public JPanel getPanel() {
		rootPanel = new JPanel();
		rootPanel.setLayout(new BoxLayout(rootPanel, BoxLayout.PAGE_AXIS));

		
		String verboseLevels[] = { "Error", "Warning", "Info", "Detail", "Debug", "Stats" };
		availableVerbosityLevel = new JComboBox(verboseLevels);
		// Default value
		availableVerbosityLevel.setSelectedIndex(3);
		LogRecorder.setLogLevel(LogLevel.DETAIL);
		
		JPanel line0 = new JPanel();
		line0.setLayout(new FlowLayout());
		line0.add(textLogArea);
		line0.add(availableVerbosityLevel);
		
		availableVerbosityLevel.addActionListener(this);
		rootPanel.add(line0);
		
		
		return rootPanel;
	}

	@Override
	public int panelWidth() {
		return 600;
	}

	@Override
	public int panelHeight() {
		return 300;
	}

	@Override
	public void actionPerformed(ActionEvent ie) {
		if (ie.getSource().equals(availableVerbosityLevel)) {
			String level = (String) availableVerbosityLevel.getSelectedItem();
			LogLevel verbosityLevel;
			if (level.equals("Error")) {
				verbosityLevel = LogLevel.ERROR;
			} else if (level.equals("Warning")) {
				verbosityLevel = LogLevel.WARNING;
			} else if (level.equals("Info")) {
				verbosityLevel = LogLevel.INFO;
			} else if (level.equals("Detail")) {
				verbosityLevel = LogLevel.DETAIL;
			} else if (level.equals("Debug")) {
				verbosityLevel = LogLevel.DEBUG;
			} else if (level.equals("Stats")) {
				verbosityLevel = LogLevel.STATS;
			} else {
				LogRecorder.log(LogLevel.WARNING, "Verbosity level '" + level
						+ "' unknown. Setting default to INFO");
				verbosityLevel = LogLevel.INFO;
			}
			LogRecorder.setLogLevel(verbosityLevel);
		}
		
	}
}
